home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
oleo130s.zip
/
OLEO130S.TAR
/
oleo-1.3
/
utils.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-26
|
20KB
|
1,189 lines
/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
This file is part of Oleo, the GNU Spreadsheet.
Oleo is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Oleo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <errno.h>
#include "sysdef.h"
/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(DIRENT) || defined(_POSIX_VERSION)
#include <dirent.h>
#define NLENGTH(dirent) (strlen((dirent)->d_name))
#else /* not (DIRENT or _POSIX_VERSION) */
#define dirent direct
#define NLENGTH(dirent) ((dirent)->d_namlen)
#ifdef SYSNDIR
#include <sys/ndir.h>
#endif /* SYSNDIR */
#ifdef SYSDIR
#include <sys/dir.h>
#endif /* SYSDIR */
#ifdef NDIR
#include <ndir.h>
#endif /* NDIR */
#endif /* not (DIRENT or _POSIX_VERSION) */
#ifdef __STDC__
#define CONST const
#undef NULL
#else
#define CONST
#endif
#include <ctype.h>
#include "utils.h"
#ifndef F_OK
#define F_OK 0
#endif
#ifndef _IOSTRG
#define _IOSTRG 0
#endif
#ifdef __STDC__
extern void abort (void);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
extern void *realloc (void *, size_t);
#else
extern void abort ();
extern void *malloc ();
extern void *calloc ();
extern void *realloc ();
#endif
extern int sys_nerr;
extern char *sys_errlist[];
struct id
{
int flag;
FILE *fp;
char *name;
};
struct id *__id_s;
int __id_n;
int __id_f;
int __make_backups;
int __backup_by_copying;
/* Stash argv[0] here so panic will know what the program is called */
char *argv_name = 0;
/* Blow chunks! */
#ifdef __STDC__
void
panic (const char *s,...)
#else
void
panic (s, va_alist)
char *s;
va_dcl
#endif
{
va_list iggy;
var_start (iggy, s);
if (argv_name)
fprintf (stderr, "%s:", argv_name);
vfprintf (stderr, s, iggy);
putc ('\n', stderr);
va_end (iggy);
exit (2);
}
/* Given a file name, come up with a backup file name. . . */
#ifdef __STDC__
char *
backup_file_name (char *file_name)
#else
char *
backup_file_name (file_name)
char *file_name;
#endif
{
char *dir_name, *dir_end;
DIR *dir;
register struct dirent *dp;
int len;
int max_fnum;
int cur_fnum;
char *tmp_ptr;
char *return_value;
dir_end = (char *)rindex (file_name, '/');
if (dir_end)
{
dir_name = file_name;
file_name = dir_end + 1;
*dir_end = '\0';
}
else
{
dir_name = ".";
}
len = strlen (file_name);
dir = opendir (dir_name);
if (dir == 0)
{
if (dir_end)
*dir_end = '/';
return (char *) 0;
}
max_fnum = 0;
while (dp = readdir (dir))
{
if (!dp->d_ino
|| NLENGTH (dp) <= len
|| strncmp (dp->d_name, file_name, len)
|| dp->d_name[len] != '.'
|| dp->d_name[len + 1] != '~'
|| dp->d_name[NLENGTH(dp) - 1] != '~')
continue;
tmp_ptr = &(dp->d_name[len + 2]);
for (cur_fnum = 0; isdigit (*tmp_ptr); tmp_ptr++)
cur_fnum = cur_fnum * 10 + *tmp_ptr - '0';
if (tmp_ptr != &(dp->d_name[NLENGTH(dp) - 1]) || cur_fnum < max_fnum)
continue;
max_fnum = cur_fnum;
}
closedir (dir);
max_fnum++;
return_value = (char *) malloc (strlen (dir_name) + len + 12);
if (!return_value)
return (char *) 0;
sprintf (return_value, "%s/%s.~%d~", dir_name, file_name, max_fnum);
if (dir_end)
*dir_end = '/';
return return_value;
}
char *
__fp_name (fp)
FILE *fp;
{
int n;
for (n = 0; n < __id_n; n++)
{
if (__id_s[n].fp == fp)
return __id_s[n].name;
}
return "{Unknown file pointer}";
}
void
__set_fp (fp, name, flag)
FILE *fp;
CONST char *name;
int flag;
{
if (__id_s == 0)
{
__id_s = ck_malloc (20 * sizeof (struct id));
__id_n = 0;
__id_f = 20;
}
else
{
int n;
for (n = 0; n < __id_n; n++)
if (__id_s[n].fp == fp)
{
free (__id_s[n].name);
__id_s[n] = __id_s[--__id_n];
__id_f++;
break;
}
}
if (__id_f == 0)
{
__id_f = 20;
__id_s = ck_realloc (__id_s, (__id_f + __id_n) * sizeof (struct id));
}
__id_s[__id_n].flag = flag;
__id_s[__id_n].name = strdup (name);
__id_s[__id_n].fp = fp;
__id_n++;
__id_f--;
}
/* Open a file or a pipe */
FILE *
xopen (name, mode)
CONST char *name;
CONST char *mode;
{
int flag = 0;
FILE *ret;
while (*name == ' ')
name++;
if (*name == '!')
{
name++;
ret = popen (name, mode);
flag = 1;
}
else
ret = fopen (name, mode);
if (ret == 0)
return ret;
__set_fp (ret, name, flag);
return ret;
}
/* Open a file, creating a backup file if needed. . . */
FILE *
fopen_with_backup (name, mode)
char *name;
CONST char *mode;
{
char *newname;
struct stat stat_buf;
int old_file = 0;
old_file = (stat (name, &stat_buf) >= 0);
if (__make_backups && *mode == 'w' && access (name, F_OK) == 0)
{
newname = backup_file_name (name);
if (!newname)
return (FILE *) 0;
if (__backup_by_copying)
{
FILE *c_in, *c_out;
int n_read;
char buf[4096];
c_in = fopen (name, "r");
if (!c_in)
return 0;
c_out = fopen (newname, "w");
{
int fd;
if (!old_file || (stat (name, &stat_buf) < 0))
{
fclose (c_in);
return 0;
}
fd = creat (newname, stat_buf.st_mode);
if (fd < 0)
{
fclose (c_in);
return 0;
}
fchmod (fd, stat_buf.st_mode);
c_out = fdopen (fd, "w");
if (!c_out)
{
fclose (c_in);
close (fd);
return 0;
}
}
while ((n_read = fread (buf, 1, sizeof (buf), c_in)) > 0)
if (fwrite (buf, 1, n_read, c_out) != n_read)
{
fclose (c_in);
fclose (c_out);
return (FILE *) 0;
}
if (fclose (c_in) == EOF || fclose (c_out) == EOF)
return (FILE *) 0;
}
else
#if defined(HAVE_RENAME)
if (rename (name, newname) < 0)
#else
if (link (name, newname) || unlink (name))
#endif
return (FILE *) 0;
free (newname);
}
{
FILE * ret = fopen (name, mode);
if (ret && old_file)
fchmod (fileno (ret), stat_buf.st_mode);
return ret;
}
}
/* Open a file or a pipe, creating a backup file if it's a file */
FILE *
xopen_with_backup (name, mode)
CONST char *name;
CONST char *mode;
{
int flag;
FILE *ret;
while (*name == ' ')
name++;
if (*name == '|')
{
ret = popen (name + 1, mode);
flag = 1;
}
else
{
ret = fopen_with_backup (name, mode);
flag = 0;
}
if (ret == 0)
return ret;
__set_fp (ret, name, flag);
return ret;
}
/* Close something opened with xopen. . . */
int
xclose (fp)
FILE *fp;
{
int ret;
int n;
for (n = 0; n < __id_n; n++)
{
if (__id_s[n].fp == fp)
break;
}
if (n == __id_n)
panic ("Unknown file pointer %p given to xclose", fp);
if (__id_s[n].flag)
ret = pclose (fp);
else
ret = fclose (fp);
return ret;
}
/* Fclose or panic */
void
ck_fclose (stream)
FILE *stream;
{
if (fclose (stream) == EOF)
panic ("Couldn't close %s", __fp_name (stream));
}
/* fopen or panic */
void *
ck_malloc (size)
size_t size;
{
void *ret;
ret = malloc (size);
if (ret == (void *) 0)
panic ("Couldn't allocate %u bytes", size);
return ret;
}
#ifdef __STDC__
char *
ck_savestr (char *str)
#else
char *
ck_savestr (str)
char *str;
#endif
{
char *newstr = 0;
if (str)
{
int len = strlen (str) + 1;
newstr = (char *) ck_malloc (len);
bcopy (str, newstr, len);
}
return newstr;
}
#ifdef __STDC__
char *
ck_savestrn (char *str, int n)
#else
char *
ck_savestrn (str, n)
char *str;
int n;
#endif
{
char *newstr = 0;
if (str)
{
newstr = (char *) ck_malloc (n + 1);
bcopy (str, newstr, n);
newstr[n] = '\0';
}
return newstr;
}
#ifdef __STDC__
void *
ck_calloc (size_t size)
#else
void *
ck_calloc (size)
size_t size;
#endif
{
void *ret;
ret = calloc (size, 1);
if (ret == (void *) 0)
panic ("Couldn't allocate %u bytes", size);
return ret;
}
/* Realloc or panic */
#ifdef __STDC__
void *
ck_realloc (void *ptr, size_t size)
#else
void *
ck_realloc (ptr, size)
void *ptr;
size_t size;
#endif
{
void *ret;
if (!ptr)
ret = malloc (size);
else
ret = realloc (ptr, size);
if (ret == (void *) 0)
panic ("Couldn't re-allocate %u bytes from %p", size, ptr);
return ret;
}
/* Do a sprintf into an allocated buffer. */
char *
#ifdef __STDC__
mk_sprintf (char *str,...)
{
va_list iggy;
#ifdef __TURBOC__
static
#endif
char tmpbuf[1024 * 8];
char *ret;
va_start (iggy, str);
vsprintf (tmpbuf, str, iggy);
va_end (iggy);
ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
strcpy (ret, tmpbuf);
return ret;
}
#else
mk_sprintf (str, va_alist)
char *str;
va_dcl
{
va_list iggy;
#ifdef __TURBOC__
static
#endif
char tmpbuf[1024 * 8];
char *ret;
va_start (iggy);
vsprintf (tmpbuf, str, iggy);
va_end (iggy);
ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
strcpy (ret, tmpbuf);
return ret;
}
#endif
/* Implement a variable sized LIFO stack of pointers to void */
struct stack
{
int allocated;
int used;
void **buf;
};
#define MIN_STACK 20
void *
init_stack ()
{
struct stack *b;
b = (struct stack *) ck_malloc (sizeof (struct stack));
b->allocated = MIN_STACK;
b->used = 0;
b->buf = (void **) ck_malloc (MIN_STACK * sizeof (void *));
return (void *) b;
}
void
flush_stack (bb)
void *bb;
{
struct stack *b;
b = (struct stack *) bb;
free (b->buf);
b->buf = 0;
b->allocated = 0;
b->used = 0;
free (b);
}
void
push_stack (bb, add)
void *bb;
void *add;
{
struct stack *b;
b = (struct stack *) bb;
if (b->allocated == b->used)
{
b->allocated *= 2;
b->buf = (void **) ck_realloc (b->buf, b->allocated * sizeof (void *));
}
b->buf[(b->used)++] = add;
}
void *
pop_stack (bb)
void *bb;
{
struct stack *b;
b = (struct stack *) bb;
if (b->used == 0)
return (void *) 0;
return b->buf[--(b->used)];
}
int
size_stack (bb)
void *bb;
{
struct stack *b;
b = (struct stack *) bb;
return b->used;
}
#ifndef HAVE_STRDUP
char *
strdup (str)
CONST char *str;
{
char *ret;
ret = (char *) ck_malloc (strlen (str) + 2);
strcpy (ret, str);
return ret;
}
#endif
#ifndef HAVE_STRICMP
/*
* stricmp - compare string s1 to s2, ignoring case
*/
#ifdef __STDC__
int
stricmp (const char * s1, const char * s2)
#else
int
stricmp (s1, s2)
CONST char *s1;
CONST char *s2;
#endif
{
register CONST char *scan1;
register CONST char *scan2;
register char chr1, chr2;
scan1 = s1;
scan2 = s2;
do
{
chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
scan1++;
scan2++;
}
while (chr1 && chr1 == chr2);
/*
* The following case analysis is necessary so that characters
* which look negative collate low against normal characters but
* high against the end-of-string NUL.
*/
if (chr1 == '\0' && chr2 == '\0')
return 0;
else if (chr1 == '\0')
return -1;
else if (chr2 == '\0')
return 1;
else
return chr1 - chr2;
}
#endif
#ifndef HAVE_STRINCMP
/* strincmp - compare first N chars of strings S1 and S2 */
#ifdef __STDC__
int
strincmp (const char * s1, const char * s2, size_t n)
#else
int
strincmp (s1, s2, n)
CONST char *s1;
CONST char *s2;
size_t n;
#endif
{
register CONST char *scan1;
register CONST char *scan2;
register size_t count;
register char chr1, chr2;
scan1 = s1;
scan2 = s2;
count = n;
do
{
chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
scan1++;
scan2++;
}
while (--count != 0 && chr1 && chr1 == chr2);
/* if (count == (size_t)-1)
return 0; */
/*
* The following case analysis is necessary so that characters
* which look negative collate low against normal characters but
* high against the end-of-string NUL.
*/
if (chr1 == '\0' && chr2 == '\0')
return 0;
else if (chr1 == '\0')
return -1;
else if (chr2 == '\0')
return 1;
else
return chr1 - chr2;
}
#endif
#ifndef HAVE_STRSTR
CONST char *
strstr (s, wanted)
CONST char *s;
CONST char *wanted;
{
register CONST char *scan;
register size_t len;
register char firstc;
/*
* The odd placement of the two tests is so "" is findable.
* Also, we inline the first char for speed.
* The ++ on scan has been moved down for optimization.
*/
firstc = *wanted;
len = strlen (wanted);
for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
if (*scan++ == '\0')
return (char *) 0;
return scan;
}
#endif
#ifdef __STDC__
char *
err_msg (void)
#else
char *
err_msg ()
#endif
{
int n;
static char buf[80];
n = errno;
if (n < sys_nerr)
return sys_errlist[n];
sprintf (buf, "Unknown error code %d (%#x)", n, n);
return buf;
}
/* Take a quoted string and return the character it represents */
#ifdef __STDC__
int
string_to_char (char ** ptr)
#else
int
string_to_char (ptr)
char **ptr;
#endif
{
char *str;
int i;
char c1, c2;
str = *ptr;
if (str[0] == '\\')
{
switch (str[1])
{
case ' ':
i = ' ';
break;
case '\\':
i = '\\';
break;
case 'b':
i = '\b';
break;
case 'f':
i = '\f';
break;
case 'n':
i = '\n';
break;
case 'r':
i = '\r';
break;
case 't':
i = '\t';
break;
case 'x':
c1 = str[2];
c2 = str[3];
if (isxdigit (c1))
{
if (isdigit (c1))
c1 -= '0';
else if (isupper (c1))
c1 -= 'A';
else
c1 -= 'a';
if (isxdigit (c2))
{
if (isdigit (c2))
c2 -= '0';
else if (isupper (c2))
c2 -= 'A';
else
c2 -= 'a';
i = c1 * 0x10 + c2;
str++;
}
else
i = c1;
}
else
i = 'x';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (str[2] >= '0' && str[2] <= '7')
{
if (str[3] >= '0' && str[3] <= '7')
{
i = (str[1] - '0') * 0100 + (str[2] - '0') * 010 + (str[3] - '0');
str += 2;
}
else
{
i = (str[1] - '0') * 010 + (str[2] - '0');
str++;
}
}
else
i = str[1] - '0';
break;
default:
i = str[0];
--str;
break;
}
str += 2;
*ptr = str;
return i;
}
if (str[0] == 'M' && str[1] == '-')
{
i = 0x80;
str += 2;
}
else
i = 0;
if (str[0] == '^')
{
if (str[1] == '?')
i += 0x7f;
else if (str[1] >= '@' && str[1] <= '_')
i |= str[1] - '@';
else if (str[1] >= 'a' && str[1] <= 'z')
i = str[1] - 'a' + 1;
else if (str[1] == '\0' || isspace (str[1]))
i = '^';
else
return -1;
str += 2;
}
else
{
i |= str[0];
str++;
}
*ptr = str;
return i;
}
/* Take a char and turn it into a readable string */
#ifdef __STDC__
char *
char_to_string (int ch)
#else
char *
char_to_string (ch)
int ch;
#endif
{
static char buf[5] = "M-";
if (ch >= ' ' && ch <= '~')
{
buf[3] = ch;
return &buf[3];
}
if (ch & 0x80)
{
ch &= 0x7f;
if (ch == 0x7f || ch < ' ')
{
buf[2] = '^';
buf[3] = (ch == 0x7f ? '?' : ch + '@');
}
else
{
buf[2] = ch;
buf[3] = '\0';
}
return &buf[0];
}
if (ch == 0x7f || ch < ' ')
{
buf[2] = '^';
buf[3] = (ch == 0x7f ? '?' : ch + '@');
return &buf[2];
}
return "huh";
}
#ifdef __STDC__
long
astol (char **ptr)
#else
long
astol (ptr)
char **ptr;
#endif
{
register long i = 0;
register int c;
int sign = 1;
char *s;
s = *ptr;
/* Skip whitespace */
while (isspace (*s))
if (*s++ == '\0')
{
*ptr = s;
return (0);
}
/* Check for - or + */
if (*s == '-')
{
s++;
sign = -1;
}
else if (*s == '+')
s++;
/* Read in the digits */
for (; c = *s; s++)
{
if (!isdigit (c) || i > 214748364 || (i == 214748364 && c > (sign > 0 ? '7' : '8')))
break;
i = i * 10 + c - '0';
}
*ptr = s;
return i * sign;
}
/*
* astof - accept a number of the form:
* (and ignores leading white space)
*
* null ::=
* digit ::= 0|1|2|3|4|5|6|7|8|9
* digits ::= <digit>*
* DIGITS ::= <digit>+
* sign ::= <null> | + | -
* -------------------------------
* accepted:
* -------------------------------
* integer ::= <sign><DIGITS>
* real ::= <integer> . <digits> | <null> . <DIGITS>
* epart ::= e <integer> | E <integer>
* float ::= <integer> <epart> | <real> <epart>
*
* Always returned as a double
*
* There is no particular attempt to reduce mpys/divs
* those machines that are still out there (eg. PDP11/Small)
* that shun floating point arithmetic might rethink this routine.
*/
static double exps0[10] =
{1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
static double exps1[10] =
{1E00, 1E10, 1E20, 1E30
#ifndef vax
,1E40, 1E50, 1E60, 1E70, 1E80, 1E90
#endif
};
#define REGISTER register
#ifdef __STDC__
double
astof (char **sp)
#else
double
astof (sp)
char **sp;
#endif
{
REGISTER char *s;
REGISTER char *cp;
long ipart, epart;
int neg = 0;
double res;
int n;
s = *sp;
while (isspace (*s))
{
s++;
if (*s == '\0')
{
*sp = s;
return (0.0);
}
}
/*
* Need to handle sign here due to '-.3' or '-0.3'
*/
if (*s == '-')
{
++neg;
++s;
}
else if (*s == '+')
++s;
cp = s;
/*
* get ipart handling '.n' case
*/
res = 0.0;
while (isdigit (*s))
{
for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
ipart = ipart * 10 + *s++ - '0';
res = res * exps0[n] + (double) ipart;
}
if (s == cp)
{
if (*s == '.')
ipart = 0;
else
{
*sp = s;
return (0.0);
}
}
/*
* either we find a '.' or e|E or done
*/
if (*s == '.')
{
int m;
++s;
m = 0;
while (isdigit (*s))
{
for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
ipart = ipart * 10 + *s++ - '0';
m += n;
if (m >= 100)
continue;
if (m >= 10)
res += ((double) ipart) / (exps1[m / 10] * exps0[m % 10]);
else
res += ((double) ipart) / exps0[m];
}
}
/*
* In either case (.) handle E part
*/
if (*s == 'e' || *s == 'E')
{
int eneg;
++s;
epart = 0;
eneg = 0;
if (*s == '-')
{
eneg++;
s++;
}
else if (*s == '+')
s++;
while (isdigit (*s))
epart = epart * 10 + *s++ - '0';
if (eneg)
{
#ifndef vax
while (epart >= 100)
{
res /= 1E100;
epart -= 100;
}
#endif
if (epart > 9)
{
res /= exps1[epart / 10];
epart %= 10;
}
if (epart)
res /= exps0[epart];
}
else
{
#ifndef vax
while (epart >= 100)
{
res *= 1E100;
epart -= 100;
}
#endif
if (epart > 9)
{
res *= exps1[epart / 10];
epart %= 10;
}
if (epart)
res *= exps0[epart];
}
}
/*
* fix sign
*/
if (neg)
res = -res;
*sp = s;
return (res);
}
#ifdef TEST_ASTOF
main ()
{
char buf[80];
char *ptr;
double at, ast;
double atof ();
while (gets (buf))
{
at = atof (buf);
ptr = buf;
ast = astof (&ptr);
printf ("%15.6f %15.6f %s ", at, ast, at == ast ? "eq" : "NEQ");
if (*ptr)
printf ("%s->'%s'\n", buf, ptr);
else
printf ("%s\n", buf);
}
}
char *
ck_savestr (str)
char *str;
{
char *newstr = 0;
if (str)
{
int len = strlen (str) + 1;
newstr = (char *) ck_malloc (len);
bcopy (str, newstr, len);
}
return newstr;
}
#endif